package com.xu.cloud.common.jpa;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.data.jpa.repository.support.JpaEntityInformation;
import org.springframework.data.jpa.repository.support.JpaEntityInformationSupport;
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import javax.persistence.EntityManager;
import java.util.Objects;
import java.util.Optional;

/**
 * SimpleJpaRepositoryV2
 *
 * @author xuguan
 * @since 2025/6/10
 */
@Repository
@Transactional(readOnly = true)
@Slf4j
public class SimpleJpaRepositoryV2<T, ID> extends SimpleJpaRepository<T, ID> implements JpaSpecificationRepositoryV2<T, ID> {
    private final JpaEntityInformation<T, ID> entityInformation;
    private final EntityManager em;

    public SimpleJpaRepositoryV2(JpaEntityInformation<T, ID> entityInformation, EntityManager entityManager) {
        super(entityInformation, entityManager);
        this.entityInformation = entityInformation;
        this.em = entityManager;
    }

    public SimpleJpaRepositoryV2(Class<T> domainClass, EntityManager em) {
        super(domainClass, em);
        this.entityInformation = (JpaEntityInformation<T, ID>) JpaEntityInformationSupport.getEntityInformation(domainClass, em);
        this.em = em;
    }

    @Transactional
    @Override
    public void saveOrUpdate(T entity) {
        Assert.notNull(entity, "Entity must not be null!");
        final ID id = entityInformation.getId(entity);
        if (Objects.isNull(id)) {
            log.info("id is null, insert data");
            em.persist(entity);
        } else {
            final Optional<T> optional = findById(id);
            if (optional.isPresent()) {
                log.info("update data");
                final T dbEntity = optional.get();
                BeanUtils.copyProperties(entity, dbEntity);
                em.merge(dbEntity);
            } else {
                log.info("insert data");
                em.persist(entity);
            }
        }
        em.flush();
    }
}
